{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "5hIbr52I7Z7U"
   },
   "source": [
    "Deep Learning\n",
    "=============\n",
    "\n",
    "Assignment 1\n",
    "------------\n",
    "\n",
    "The objective of this assignment is to learn about simple data curation practices, and familiarize you with some of the data we'll be reusing later.\n",
    "\n",
    "This notebook uses the [notMNIST](http://yaroslavvb.blogspot.com/2011/09/notmnist-dataset.html) dataset to be used with python experiments. This dataset is designed to look like the classic [MNIST](http://yann.lecun.com/exdb/mnist/) dataset, while looking a little more like real data: it's a harder task, and the data is a lot less 'clean' than MNIST."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "collapsed": true,
    "id": "apJbCsBHl-2A"
   },
   "outputs": [],
   "source": [
    "# These are all the modules we'll be using later. Make sure you can import them\n",
    "# before proceeding further.\n",
    "from __future__ import print_function\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import os\n",
    "import sys\n",
    "import tarfile\n",
    "from IPython.display import display, Image\n",
    "from scipy import ndimage\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from six.moves.urllib.request import urlretrieve\n",
    "from six.moves import cPickle as pickle\n",
    "\n",
    "# Config the matplotlib backend as plotting inline in IPython\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "jNWGtZaXn-5j"
   },
   "source": [
    "First, we'll download the dataset to our local machine. The data consists of characters rendered in a variety of fonts on a 28x28 image. The labels are limited to 'A' through 'J' (10 classes). The training set has about 500k and the testset 19000 labelled examples. Given these sizes, it should be possible to train models quickly on any machine."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     },
     "output_extras": [
      {
       "item_id": 1
      }
     ]
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 186058,
     "status": "ok",
     "timestamp": 1444485672507,
     "user": {
      "color": "#1FA15D",
      "displayName": "Vincent Vanhoucke",
      "isAnonymous": false,
      "isMe": true,
      "permissionId": "05076109866853157986",
      "photoUrl": "//lh6.googleusercontent.com/-cCJa7dTDcgQ/AAAAAAAAAAI/AAAAAAAACgw/r2EZ_8oYer4/s50-c-k-no/photo.jpg",
      "sessionId": "2a0a5e044bb03b66",
      "userId": "102167687554210253930"
     },
     "user_tz": 420
    },
    "id": "EYRJ4ICW6-da",
    "outputId": "0d0f85df-155f-4a89-8e7e-ee32df36ec8d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Attempting to download: notMNIST_large.tar.gz\n",
      "0%....5%....10%....15%....20%....25%....30%....35%....40%....45%....50%....55%....60%....65%....70%....75%....80%....85%....90%....95%....100%\n",
      "Download Complete!\n",
      "Found and verified ./notMNIST_large.tar.gz\n",
      "Attempting to download: notMNIST_small.tar.gz\n",
      "0%....5%....10%....15%....20%....25%....30%....35%....40%....45%....50%....55%....60%....65%....70%....75%....80%....85%....90%....95%....100%\n",
      "Download Complete!\n",
      "Found and verified ./notMNIST_small.tar.gz\n"
     ]
    }
   ],
   "source": [
    "url = 'http://yaroslavvb.com/upload/notMNIST/'\n",
    "\n",
    "def maybe_download(filename, expected_bytes, force=False):\n",
    "  \"\"\"Download a file if not present, and make sure it's the right size.\"\"\"\n",
    "  if force or not os.path.exists(filename):\n",
    "    filename, _ = urlretrieve(url + filename, filename)\n",
    "  statinfo = os.stat(filename)\n",
    "  if statinfo.st_size == expected_bytes:\n",
    "    print('Found and verified', filename)\n",
    "  else:\n",
    "    raise Exception(\n",
    "      'Failed to verify' + filename + '. Can you get to it with a browser?')\n",
    "  return filename\n",
    "\n",
    "train_filename = maybe_download('notMNIST_large.tar.gz', 247336696)\n",
    "test_filename = maybe_download('notMNIST_small.tar.gz', 8458043)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "cC3p0oEyF8QT"
   },
   "source": [
    "Extract the dataset from the compressed .tar.gz file.\n",
    "This should give you a set of directories, labelled A through J."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     },
     "output_extras": [
      {
       "item_id": 1
      }
     ]
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 186055,
     "status": "ok",
     "timestamp": 1444485672525,
     "user": {
      "color": "#1FA15D",
      "displayName": "Vincent Vanhoucke",
      "isAnonymous": false,
      "isMe": true,
      "permissionId": "05076109866853157986",
      "photoUrl": "//lh6.googleusercontent.com/-cCJa7dTDcgQ/AAAAAAAAAAI/AAAAAAAACgw/r2EZ_8oYer4/s50-c-k-no/photo.jpg",
      "sessionId": "2a0a5e044bb03b66",
      "userId": "102167687554210253930"
     },
     "user_tz": 420
    },
    "id": "H8CBE-WZ8nmj",
    "outputId": "ef6c790c-2513-4b09-962e-27c79390c762"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large already present - Skipping extraction of ./notMNIST_large.tar.gz.\n",
      "['./notMNIST_large/A', './notMNIST_large/B', './notMNIST_large/C', './notMNIST_large/D', './notMNIST_large/E', './notMNIST_large/F', './notMNIST_large/G', './notMNIST_large/H', './notMNIST_large/I', './notMNIST_large/J']\n",
      "./notMNIST_small already present - Skipping extraction of ./notMNIST_small.tar.gz.\n",
      "['./notMNIST_small/A', './notMNIST_small/B', './notMNIST_small/C', './notMNIST_small/D', './notMNIST_small/E', './notMNIST_small/F', './notMNIST_small/G', './notMNIST_small/H', './notMNIST_small/I', './notMNIST_small/J']\n"
     ]
    }
   ],
   "source": [
    "num_classes = 10\n",
    "np.random.seed(133)\n",
    "\n",
    "def maybe_extract(filename, force=False):\n",
    "  root = os.path.splitext(os.path.splitext(filename)[0])[0]  # remove .tar.gz\n",
    "  if os.path.isdir(root) and not force:\n",
    "    # You may override by setting force=True.\n",
    "    print('%s already present - Skipping extraction of %s.' % (root, filename))\n",
    "  else:\n",
    "    print('Extracting data for %s. This may take a while. Please wait.' % root)\n",
    "    tar = tarfile.open(filename)\n",
    "    sys.stdout.flush()\n",
    "    tar.extractall(data_root)\n",
    "    tar.close()\n",
    "  data_folders = [\n",
    "    os.path.join(root, d) for d in sorted(os.listdir(root))\n",
    "    if os.path.isdir(os.path.join(root, d))]\n",
    "  if len(data_folders) != num_classes:\n",
    "    raise Exception(\n",
    "      'Expected %d folders, one per class. Found %d instead.' % (\n",
    "        num_classes, len(data_folders)))\n",
    "  print(data_folders)\n",
    "  return data_folders\n",
    "  \n",
    "train_folders = maybe_extract(train_filename)\n",
    "test_folders = maybe_extract(test_filename)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "4riXK3IoHgx6"
   },
   "source": [
    "---\n",
    "Problem 1\n",
    "---------\n",
    "\n",
    "Let's take a peek at some of the data to make sure it looks sensible. Each exemplar should be an image of a character A through J rendered in a different font. Display a sample of the images that we just downloaded. Hint: you can use the package IPython.display.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First of all, let's import some libraries that I will use later on and activate online display of matplotlib outputs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "import hashlib\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def disp_samples(data_folders, sample_size):\n",
    "  for folder in data_folders:\n",
    "    print(folder)\n",
    "    image_files = os.listdir(folder)\n",
    "    image_sample = random.sample(image_files, sample_size)\n",
    "    for image in image_sample:\n",
    "      image_file = os.path.join(folder, image)\n",
    "      i = Image(filename=image_file)\n",
    "      display(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/A\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAB10lEQVR4nGWSO2hUURCGv5m5d9WF\nPA3BIhuiJGgKH0FTBFGUPDQ2aVQQBU0EERSxslAipNZGxELBUgQbrQUlgkFhG1FEC62MSBIjBCSa\n3b1nLO5NNrtOc4bzcf75Z+ZIR0u+rcV+z35YFqcu5Haxa3GhvGy9DyqhHvIsO/vOYv/Bue0Wm2nE\nyBBax7TtYOJJEir2fPOOUE9XnqZyIvGZVqQWzi82pFdC68moDn714cyJ0n20tqyW/FgmFvTLUn9N\nWQ0yHCdk9E371hr63pO+NTHJHW9aZ0or6EgKBShND9k6WIZRAoALrj8/DlaFtYT3dwYF63Ih6OdS\n1ZSal/OHUSw5MuBK0OlthbCqfN9X/AmKsvN13gShYSIvGW3/FsJcE4Iycw8Doef02oJOedlHMUzG\nfBcGxuBIRo0X7neJQHIL35tFwBjvTbsz9pbCpxgQBi5sQUAkf605LWs89GRfzcSV3qupsErhV7hO\nBFgUmSlgnBhLacSkv5Lq0AQwudGDAqKNs387ow1xHG88P3mpmziKc3Hh1qbM07hfTF+9c5/vSdM9\n59L9qBQ7HkeOhAO7ofhWA8jK0OWs1/2excs7M6upT0n2H24eas7rn6UfV+Yap3IC4PboH6EKnOcm\nDJCnAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/B\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABy0lEQVR4nG2SO2iUQRSFvzszu0lY\nSIRdE1bER6UikkYtgtr5qGRRxNomFmKnhYWliI02aVJYqEVAlhAhlU0KQSw0giKmsFBTaOIrEsXs\n/jNzLGLImuxpbvHdB+dwbbA+NFir1qq9rXa7EMSf31+9/iwnAQ+VtFHfmsdxBkwrSSnGGNPKwuLi\nlxXlLGliAIORM6dODj9SVNSLvq3V6o5LP5RioZleDKDEuApFPcOB55yycks38M5571d7MMxMvvnG\nspW4sCW5nFJCAAhJWXqHMOp7cGzWr9XS0wUauwGxNPcfNLz35TR8EEfBvUUfOqBI2VLlTjmh8tPr\n5NAxV9lXyb0HLu/PXtYcXTat+1xTTiqmDhM8dK5d2yC37XR+biYDSsX4aAzZfbjVI1c9dgSM/ODK\nV7cpPuPERxVF1NtdG6yEELx/3PgdvC/23nedUMQYYyrP3iZRSkcvdokvMtkKwjjfBYq5BYRjuCts\nRwD6ukBjqB9DfOoCAyO1bGSeBBzu3yc4vIEVfVcBueLueghJ8zUMozqlpFjoJqFcq/RrJ4bT9smJ\n+Vw7dLYeTc7GrjkaS61NTy3pZQNnoTIgyVaPJgzpz/L72emZtpP+AqxyDHLhiH0PAAAAAElFTkSu\nQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/C\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABqklEQVR4nHXSMWiTURTF8f+978tn\nm1gQS2MpRhRssREUiiIWBFEc1E0j4mALgiLi5FrQRTp2ctFF0F0kg07WQQQLghSLBgdrC4JEMWgb\nadPkOw4pWNPkrL93z4PLNQBwa5AeOXFkOBeRfJt79fRD0nM2ZwCEREPjFwZl5S8/V7t6927jxcux\noWcAFth5v6pk+tpwBoDu/bc+aU0TTbv0XSqOYIBHAYzeRdVGwZxJafkK5pGbAWYeU9RcGpwpNX6f\nJAr8S+CqpiBwQzWdJ2ZjjIH5w0D+V6J7RLTEswY8ln7k8FY0M8gvJ3pAaDUw8HOZOk82Ewh8lFSl\nhNoxLEilGGtr3ieqNWs/6XGHRgCvOt2ROtR+hR0Dnf6cZW17vhNOA4UOSN+iVNmzeX0QHO5oRY8I\nrbPmAFtLWtV1Uv+rBU6fIXB0SfX6GGHj8t2Z0E0InFpSTZNbsBB8/RpJPdRMBAQOvldd7wpxsy9y\no+e5dHH9Xfp2RYk+3j2ejQBj12upiBmAk/RfLhzokv2ZL1fJ9A9GKzPjC03EvEEqf+zQvt1ZIyl/\nnn3ztiT0F/Ohlr+7ZzbJAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/D\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABwUlEQVR4nFXQu2tUQRTH8e+5M1l8\ncb1CCjE2giEkq26UYBDdSlE7FRuxsHVLBf8Be20kVQoRixAQwcYVERURSdBoCo1gUNTCIijuxE3M\nvu4ei/uY61Tz43POnMMAINQ11vx0fs7fOooIJDjb/u0aG9ptOOfcWqzavb+LIFGCMIxKdb3JjjAM\nB0fOzLT18+7UEIQt3/QsJqnl5Io+IFfLEW3uxYiIBHaA89o/navhsi5SiM91OvC5ynz6KgBPmMhQ\n4oEDvEE8vmcoR4bH+gv0Pa6y3eN+83UZ9biJtsdjvG4FBRzEpSg9xnmHX08Y5keGDI0zV3hVGWMp\nx8q2lU9+H4k3l/mQ4ySLv/xIYbTcfZFizMR/IwNO8DbtFI0O8aowsscpXvaSu6Gqf/b4TkNVdTIN\nlis6V/g7w219lOWAWZ3yv2443NJzaRZKy3oRm60q5qnWfePBuLMvGymW69qsZNFyST+atDSw1FSv\nYgAREcu03sWISGCNcK2jN5K+pHxBa8lIYeSe6hSBAJgwjEqVdT1uozDcWb4ws64bNUzS82yt4RpN\n7a8659xfVW3dGc3MRltVAAkBWt+/PH64JCZOFv0H9auruUbx8zQAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/E\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAACDUlEQVR4nFWSy0vUcRTFP/f7/c7D\nUROdBBOFrBbVagh7uDOIliEhQfTAbWCrdtGiv0Bo0aK2EQSte2BkixaCRYUtzJCEMh/RiJPmyPzm\ne2+LnzZ6lvdy7r3nnAt7IOI97ubS24LIdsU555z3ITiAE6/N7CweAji1BrVz4MpQVtUXEQighUPO\nhJbu3t6ewwc70FrGSQUDPCdnbBcSMzPTYzjAM27VRFVjbatmZvb78bV3ttSGQFB6yadnwc/p9x8m\nVyj1r24CBLHRG9Z0PoO+eDX1eQPIxcj+feXGkbfN7gK44CVwx5LjOHDgQtY/g48u70Xr0aBM6NqR\nok4TdTmtRxEDWIMiAg5AvAm1ELyZA2OFWIC0KTHmhdb6Vsy3KCif1v0SO7Z1nB43nRkbezK/fAmP\n49bTptR4x+CPhkFvcJAGIgScXu6pZj0xEcj9RcCcqIkJeIb1P7F8Dr+jPZdOOHXxepfMPVr89Wdu\nIRWD077n99PhXDAb2V6UwvPQvgTAAl9NkuDrmG4/h7YPaSYAqLYKIIK4VJ+v9XeyHAC8tEGlXm8E\nERk1mQriTRMGsavNkJHmzmKxvSDl7gGVCQAOjKyp2l7Udb4lNA2XzhztAKKihog4gWiaf7nBAzOz\nWhLjHpaZVUsSStSyZABdXJidX12rVNY3qtm+I/mJaZHhe10rk5nN79Oz33a9DYDYPyerG2OkW4yM\nAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/F\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABxElEQVR4nGVSPWtUQRQ9d97s201C\nNlkiG78CSbQIQQxRDEQWGy0EA1pYmUotBBubRCws0lhqIYJNIGn8B0EQtFIsAomKEVy0EBHSiJps\n2LgvM/dYvLfv5a23mTNz7px7z53BC6oyFxr9+rwyPwwDDJ24/JHqfEcCd+6LAAZTjvnLqs57PgJM\nYApf+Ow193wunOoFq4C28DysiUEuovC6jVH56ZUJkRgbBSCVHpxJSMHVYgK12SNGTNf5x0MAgA3e\nRtiW6z5XBIAAC7TtM8aigbu0NPZjdOZIf3nye0YyAbWuxtE3hyg+WEzJpBlXmvnLAwcjRWnrSdq/\nsdZaA8yN7vS+fxkWSrzzIZN1gLBy7y4EuHZrYnP5nUmtVM9WB8rHpgd9IMTvBwCMJmRrYL2qzWIB\nSkBAC6giqdmcrer2cN/Juc042zmniElBeQzG6u6nh1Nr0LyBOhstslGBLeAUfx5u6yVLd0gA8Ht2\nfaXXp/YSI5nM2/brpGS6V6z+kf25qNNT2ahAAITH08F0zBZA9DWb9H/kviMrBj6uKAECheZ8Gow3\nqaTyIoIOkZHajQ0qSeW3m6fHR3J1XtFr+s2jVr0vs4V/m6vpVEqJKnYAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/G\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAA9UlEQVR4nLWTMUoEQRBFX9X0sLiI\nCJoIIngGE8HUQNhbiJGnMDUx8hKeS1SWBUPRnen6BjO7zszOGumPuvvTr6lf1ZRcLBSKvmrNKEjV\n1dOeDKOn5iDdPkzC0ad6ZkxrwLJhsvlsUfZse/sAckhZzwdDMEByALzAB2AgrdfRNwF8E/YXZhrs\nrfjFVL3VNJ3cVZ2CJSnr5RADCs6UtdYQ2yhrBBu83lde799MZRvY5mGO5ooxrBX4svStpTi53fxz\ntv7TbI/VjRRmQORus9sMSFGEG+Xp7nrAbHnc8uz6cSccfXWHxCarRC7fmzhGRMn5fOM7tOY3JVGp\nYJ0qq4UAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/H\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAZklEQVR4nN2RsQ2AMAwEzyGCKkMw\nDQMwJ7NQpWaMCERimhQorhAN4ss76fWW0awRoYkQNatr8T0/kh4QOm2wnFKlko1EqwxTb+QRAGnx\ng0HFbfNgavdlLM4DaTXlounVKZ/7yufkBe//IfvPmSkmAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/I\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAlklEQVR4nO3NMQrCQBQE0PnrBBKM\noCBKREEPIIK9V/UINtb2XiFlIChbKaIYdN21s3D/CcQp5zGMbDEYFS18x9XVAVxjuerH+Cx3e7DC\n+Boig7/UJWhxbhTE63EHLU4aBtfcQAfvtWUIHkbpP/njbyENRDQQMWCOlIoK0zaYI0s0TLIOOMe0\nqxyb3mwB2WA4KRihO9YWb9AqK1IerTW9AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_large/J\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABcUlEQVR4nGWSr4tVQRiGn5m5F1nE\nBVlko1FEEC+IaLCsoCioxSgmi8FqNNs0aDD4B2zx1tUN/ggiiuGqWC0iFxGTa7hnZh7DPeyec/Zt\nM++838zzzQe7ikx+1GKrUvwc6WjlUA57R5sdelo9/MCiWnx/cn3c88KI2zZq1TPE0E8mnpvV7FtS\nDL07Q1k7RwRkSqgOgtcsajVPiNBPcoUKyLcZ9s2QD2wQgcqrOuoXJXG+bYCXSQzKcokMGOcfqQz1\nyaJmpyT6yciJUwRAXhD2mRdjCeBo8Xpf1cDLtj3vGCajR8+2yy2GICNumZckkwEEJDbNavENg/8g\nsPbTqmZvLkGW2zECiasWtTgb7SZDAlIg8dRGzV7fC0ZWj68TAivfLbrwcaco937VnYcpsWGxLtwe\nd55z32L2DjyxyY1bB7sYc7ONXzj9tzb6aNwbnEWpWuuHucXZBVIPcWo75P+2b4wHHkee/c7Nn6+b\nd4+1WB39B1vi3vbEi9eCAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_samples(train_folders, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/A\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABmUlEQVR4nG2RPUjVYRTGf+8H1ySu\nml7tNgUZES0Nl2poEBGCaAqjhhyUyKGGwGwIcWoLAqUgammwMKi91RoiwVEo8yPFPggk9GqS1/t/\nnwav3Pfq/6zPOc/5nedAVIaTN7Ckl+fBIphUzdC2rIu4VNExLL1J9zW0/JQ2T1TVqM1y80i5XH89\nbakht6S5DX09mKJ67kudE9LV/UiGpm/6wF3p3X4kxz3pCsfWtH16r2poXtAnZxmXHu319QxKPWS4\nJH0/VItkaJzTdB2WA5+l3tpRx4B0C4dnSJqomTQ0LuhHe8vhtnzD+ZJ0Lkby3FFpc3W9WCyur/7b\n1pPI19Awq0S7lehXKwbwADbpO87kTEY7vRda85efu/LuYHZef45W9jgeSh8j1NvSCHXee+99hkII\n6qxsNWS/aK36RsN76WVF9AxIz6p8jn6Fv6ewgCG3rFIUtiG/Ij3FAZ5R6XV8tWNMYaMdi6MrJOqK\n03Rc05Ze4CA3K81k4jQtBYWgDuCttvSq5g2OMwqJprJ2tDux/I4/hOEswYbC4/+4e63+XdQmvQAA\nAABJRU5ErkJggg==\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/B\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAB3ElEQVR4nGWSwUrUURTGf+fcO2Zi\nwlhBZUUEViDUwjKSJCF6gKIXCB+gRbueINpUs/ElTKhNtMuKiIqIAsmwMgiDwEXTMNjMvfdr8R+R\nqW93zrf4zvnxARC4q6RtdX5/e3bnFAEA40WfKakozQHgHNpQ6fdy0ubFCBgnRotDFpWCmZF23KjM\nGQS9jC0FTkegcAaQPf48IMBHZ+syjDpgjK6rSHkcr044+0dF0q9qUFHWyrDVYoyxxshXZWUtRfBy\nnhLEcit0q7B9YxjwMIKYRMAbggDBlVoO8o0FMAZXlZU1U51rg3NtFXV0E8PLxLsogw9tBwh7D2J0\na88vbULk2j/sUlHWq90YBObVlaScUkop5SxlzQ/hRDLncFDpkTEDaLZDBudos496yZKyrhOwmC4v\n5iBrfjQABg7XgeKrEx0jcFtJXTW2uB94qayi1jHcxTRgvCW4u3tcX6RULIhl/3FcIb0mlQreEQxZ\n8weCWWVlrQ17LcYYAzs/KSvpKUZkGlF8qaJu8lvjxRGPCCkyBTgnG0MFYNfkuBzF1gIF6l+U++Bl\nSR3dIwBTvVW3pyyVjt6PYBAvUBxwr74U2aitXG16Ae7/X+dmY0/VJvs+JtvuY2r9XH7yYM0pAH8B\n96ZfCYXa9n8AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/C\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABsUlEQVR4nHWTzUuUURTGf+fcN5VC\nUhSjpCIaI4pwtPYDlQSz6Q9o396gVQStWhdkLVpFBNK2MIpauJiIRCckLInc2Bf0YaDVzLzzvk+L\nd2aocXyW98dzzn3uPccAwDzVQLFwbHhnV7zx4c3Tma9OmiHcGZn6rKZSfbraj2MAnnZdvtgtqy3N\nv/9R68uNj3Wzcu5FAHCGS4q1fn00NJocufFb308ABEZWVNHzo5iFKIqiYEa+rIUeMPYs64/udRG5\nNe8QMTinScAfqaL7eKNmpojDlVkCk6pqsRfnPxm5Idj1RYkmiGiTGXBJVU0T2hm4sf21EhU6QeC0\nEr3qjPAzxDxONnXM4DiBBdTZ+lHSWHuOpnMA6mudffg22KoovgbR4FbwHTHHN/c0B3wOUWyNRItl\nJwWlivNtL+T05BxgVlXN2L8fZpFxs3YAhwkldU1BCGZg5pHTe0e3cQhcUy3Wg30YZKPgZ5c034eB\nEe6qXtXPWyeHHKw/f+FlouX9WQBzvxIrSaVv5VKpvJoq0bO9zXAWGJ1eV9qa6bfno4aPbBcOFk8d\n2r3Dqhuriw+f/Grswl/tvLeA5uDR0wAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/D\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABYUlEQVR4nHWSsUtbURTGf+eem9A3\nSRuetAQS6yaI1MHBwQ5FlxYHu7VYCkI3B1f/AZcORTp2KiguIhm1S7ZSCWZp1UEayBAIJVWnlGCS\n0+FFiObd9fvd73C+cz8xAHrXV63az+PTPyDaSzQQ43Ujyj7IjRcnC4Vu7eig2sfRT6hZHhm8jF9u\n/7b6ZozTW1jAq6r3iTD7pftv6xEq95wi6kWIP/VbKzi5NxYQp46Zin3MiIxAwHmiXdvJICkQnLiv\n9hmXCnGMVext2lgAzyur5gIQpWyrblRP4lNiOQShwlzY2eRJ2Onph6AwQT0MX1AORBGic1sMwAzr\nVgpcyDN91X6WCsVT/GVv0BSoytSFvUNHP1sdfLhpLKHcrYnzDmHhxPZiFIYLJiA8fF+1H8+RJP+Q\nM5rd+Nbu7M8jzg2WZqkZZaP48WT+adT6vnZ4jcig05JUv3P5t3FWOal1QendbvcftAODEeRRW+YA\nAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/E\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAB8UlEQVR4nE2TvUuWURjGf/c5z6uB\nhmlEGaQiCRJIhYlD0RLRKNgWDQ0tEQ39BUHQEg4OTdHSEARJWxEUOQRh9GaG9KGiKA2mfSiJkT7P\nOVfDeZ/X7uEsv+v+um4OQMZwsaV6hCLkQYpazQDo9556OHDIZHMZEHi8MHjZZADRzY8u9V5vl5iu\n68eUS1KM+QDQtx5zXXGpUqNfThrZTDXzjdP3DH1JMOahh1SVKSkUbixmv2cTtNhYgzCJEeLHFRa/\n1SCdHQl63gMNlY2ZMBdKeDSLBsg2PltxZ/E8a36WrAb7iQ6QLfyk/VLTAuNt4/W9n6uQpFx34YGW\nmko7wGLzkdTS+HHmyQXNbDrnrUw8Xhobt6Ut3UrtXHqOEZLOKoSMKjtl4QRKFszf+O7d9gdi3Vfj\n9c48Q0GfKpi3lGna21uWmMxefNVU7hWUoKO3Nd3Lq1psLttbwujDw0mfca12Ly23wKP1k9b9V6fx\nyc/7CRZ6idGyv8KIFpsxwMxNKaR5bpMB1rUWn+JwgNp7Sn/eAa5BI3tsIrX07lxKlEIf3jVwVbnO\n4sFlu7hZzrPS5j1czHOt7asd/9BSjJIU9OsAdI0q5nqFQTZwqnv4YNrSqfVZtXNwN8AEvoA3kqL+\nj0IqNIQHVvPt8N9XyIsoRf3pwME/Mks1tDLRxJIAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/F\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABvElEQVR4nG2STY9LYRTHf+c8T++d\ndGLQVGRCDIkE0ZUM6YINEWZBhIWF8AHEii8gLHwBEi+LSYiExDdgEmyGEBsSC5OQlBHzUmYmbe9t\nb59joUFv+9/+zj/nf16E8tSBdaOxZkk7SdMkzcQ5ghvxydITv/XeoVH6FUTaH56+matLIfalDcev\npW/fpc2k0+msLCwvueJi3XqVQuHOe6I+t3ingIgWOGiniCLvvfdOVVX+lSl70rUbJYQhEnZ/z2z+\nDIV+rIA42i3XGj+GmjoV+Q+qZUxOdAtU9jkXusEM/nQQgMPXqyKYtOabX2ee15ppZr125YtTVRMA\nMyU0fnxbrDcaP1/PBoSRba4zdu5y5k2Wbz9eaAanzjJrZX/THrHU2vYAlVxacbblFi4YDSLpCQAP\n1uXkrrSgygoW8k7K54lbNVjDyEGINvHldOU+aW5zCuB2fjr6bHWG7iA09vNyrkhMGOLcPk0gI8IN\nwuLNMcoENvM5FwgoJanN4uPph/j+k3mQuIOS7f11lzBkFKEJlY0f41wihaymrDJRfTEwCqBXrH6B\ns69yW+8pPjHJ+KOruefsSRB2XFo/+Hy/AcqcpQ1/dCSZAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/G\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAACDUlEQVR4nF2SMUiUYRzGf+/7fneZ\nXnegZsGFm1mBIKRILUlDEUQEBUkgQQ1FRBQN7k0SNTo0tDSUg0MqkVBt5ZZkUhGkBUUWV2dnFnrf\n975Pw3nX2bP+hv/zPP8HAHB03Hy5FP/5MH42hzPUy3Ltt0LwUtCni9aYDWxYPoklScFrsokqNTZF\nv+LgNX2qu3toSau6X4UWHKOKve4AjgElsY7hACK1bI4zfRhbuNGaoWnHaYw4MWEAortHG2TTOHIz\nTiZyhOCjb+snvyhIIeifvOa2V46a/ls7rdIRhuWUCyGsLLyamlqr5oja8q17CyprLJ3b2pJ2fWcO\n5WpuLTgGlSQa6cjk+icVtNiDrQY1JuKqFCsp/pJCvKaJGqx0e2ReoeZoNsLWVRiRvfB0cTUpfZa8\nZiwGt86t8QBb2jPfOx9Kdvag7Orv9Two19u7p72xsSGVzQF+BcpPLldYfqSg/5VoNAIbdj/OK8Qp\nC0gWUAAtz0QA1/NrKbOpODW9UPzaMybZueMG8/MHAG/kE403Y3Dsk0/0vNaPZZ7gVi4VI+cszQBl\nnLUmWLA8QISEkPjANiRKEIKw4Bl9lypnz+MiG9GJoFAbEY7D3vvkHMZgX8gnukJU1+xgorIenezq\nuq2gRPsrG6o2e+C9ghSk4Mt6BvXLdTQNfVSQvIIWdm34GDhLduDe21Jcej3cVmV/AdzuLBZcm2xd\nAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/H\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABX0lEQVR4nK2TP08UURTFf/e9NwMU\nZAmhpNiCGEsSahuVECp6Klq/A38aCys/iQUNzQYkoVY6C7OthUKiiUBkZ+bOoZidcXEDseBUN+/c\nc+65L7l8VYNa0js4GJeS9Cm9f9bbWpLJhoM/R3Dcm3u9IpP9OLz+ArBeuutXnzGWL+RebQCkPM5/\nV6FTUhYgpIyBCl0sxDymylSOgCtTBdR1tBvgtvBaAXFbIgqNXU0FwgsgAAgosXaoA16hhmwbJiBa\n5UNIbWExNuIomyJH7u3E0T+k0d+MDRu9/zcbMJTrHlzD/w3k4ePbznb3pYdJUnw77QQ77dJd2jym\nqnmp8qlV5NbYmnef9WigpyVtikxtfpFjhIARMGYyjNmu3zIgZkCIMaQZjEWRAoSEesBsZjECbJZe\n1zdrrfL5b7lXW4C9WV3Y6MlklyeXH854sT33alkmux78POfzxDnswf7EOZzfAXLJvsM0ZKI8AAAA\nAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/I\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABa0lEQVR4nG2Sz0pCQRSHfzMjtlBw\nJQQiZUQQgQuFCtpE+AAtqwdo3YP0CC3aBEFtKiIICmlRm1ZFtMnUW9d/pYaais7MaeH1ekc7u+Gb\n78z5zQwTClhcX4lNhwJ+HynZa7ea9VKxYFlVC0DquKZpsroXfmw+SSIllR5u0FopKaWqxMBzV7+a\nuOCMYVCMcS6EaB9mAWA5q/7pWpxhABfYsCdZ5wwA14rfXjYwXo1z5xi+mpkws7MAOAD9WFJjYt/O\nORDyuTUGW/dsCFHpjcHmHbmw2jcZ1dNwYUebsHbTGsGmNDwqHrARrBmQlU9eabRMvHgzfu37Bzfg\nAwCUjWkL187SiWJMO7cNL+z/eGkwvsQ8EDVDjWyRF5pZwqmQJwqYl4FHdzxRRFoaDyYfAtw142Fh\nqGJ+T7vNdvPK/J3aSrjmW5czrTQRAURaKYocRdw+qdOqqUprbTgmIywkk/FoKDglG992PvP+YX8C\nf+vuHv7PB1y2AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./notMNIST_small/J\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAABcElEQVR4nG2RvUoDQRSFz52JpPE3\nKRQsAoKIoAhqCEStBAsLxcqX8AV8FytLawsRxEIUf0CQiCkiSLQSYooQlZideyx2NrsbPdXMfHPn\nnLlXEMm68uk3u/TbAZN9zSDWSJPDeROu2Wq3LxIMYjDfolPVgC95AyQraTAx5CwA4O5DIAYprfpr\nuENG2AdLIbOoQJkigtFnOpLKxjgkXWaxTCpJx1sAQPrZOTgBoLiG+QPXosX9H6hYCPNkfirQtKXB\nVNNb1rOQdKVgeswJAKLSEfZ7FqMWXIXnKViO3q+gT4Khmm9Bs9D3C1gUnc/z0IsYa9YEYZ5bf5yE\nK2E//4OKJd8CfUQ8EWMEMCg0vOWT7Xlao0pjBDN5FQAORy6iAuQKeUgG++ySDFjLxbPcOP/oNI9n\ngDMGZJed9TjIrlLpWJVt0gVdfm7B9tIc8itQDXjwzoDKy/kEw2abSq/WyY5Nz2lxrzQ5KJ3GW/Xm\ntA6TnPIv6efBTC8S85YAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_samples(test_folders, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "PBdkjESPK8tw"
   },
   "source": [
    "Now let's load the data in a more manageable format. Since, depending on your computer setup you might not be able to fit it all in memory, we'll load each class into a separate dataset, store them on disk and curate them independently. Later we'll merge them into a single dataset of manageable size.\n",
    "\n",
    "We'll convert the entire dataset into a 3D array (image index, x, y) of floating point values, normalized to have approximately zero mean and standard deviation ~0.5 to make training easier down the road. \n",
    "\n",
    "A few images might not be readable, we'll just skip them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     },
     "output_extras": [
      {
       "item_id": 30
      }
     ]
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 399874,
     "status": "ok",
     "timestamp": 1444485886378,
     "user": {
      "color": "#1FA15D",
      "displayName": "Vincent Vanhoucke",
      "isAnonymous": false,
      "isMe": true,
      "permissionId": "05076109866853157986",
      "photoUrl": "//lh6.googleusercontent.com/-cCJa7dTDcgQ/AAAAAAAAAAI/AAAAAAAACgw/r2EZ_8oYer4/s50-c-k-no/photo.jpg",
      "sessionId": "2a0a5e044bb03b66",
      "userId": "102167687554210253930"
     },
     "user_tz": 420
    },
    "id": "h7q0XhG3MJdf",
    "outputId": "92c391bb-86ff-431d-9ada-315568a19e59"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pickling ./notMNIST_large/A.pickle.\n",
      "./notMNIST_large/A\n",
      "Could not read: ./notMNIST_large/A/RnJlaWdodERpc3BCb29rSXRhbGljLnR0Zg==.png : cannot identify image file './notMNIST_large/A/RnJlaWdodERpc3BCb29rSXRhbGljLnR0Zg==.png' - it's ok, skipping.\n",
      "Could not read: ./notMNIST_large/A/SG90IE11c3RhcmQgQlROIFBvc3Rlci50dGY=.png : cannot identify image file './notMNIST_large/A/SG90IE11c3RhcmQgQlROIFBvc3Rlci50dGY=.png' - it's ok, skipping.\n",
      "Could not read: ./notMNIST_large/A/Um9tYW5hIEJvbGQucGZi.png : cannot identify image file './notMNIST_large/A/Um9tYW5hIEJvbGQucGZi.png' - it's ok, skipping.\n",
      "Full dataset tensor: (52909, 28, 28)\n",
      "Mean: -0.12825\n",
      "Standard deviation: 0.443121\n",
      "Pickling ./notMNIST_large/B.pickle.\n",
      "./notMNIST_large/B\n",
      "Could not read: ./notMNIST_large/B/TmlraXNFRi1TZW1pQm9sZEl0YWxpYy5vdGY=.png : cannot identify image file './notMNIST_large/B/TmlraXNFRi1TZW1pQm9sZEl0YWxpYy5vdGY=.png' - it's ok, skipping.\n",
      "Full dataset tensor: (52911, 28, 28)\n",
      "Mean: -0.00756303\n",
      "Standard deviation: 0.454491\n",
      "Pickling ./notMNIST_large/C.pickle.\n",
      "./notMNIST_large/C\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: -0.142258\n",
      "Standard deviation: 0.439806\n",
      "Pickling ./notMNIST_large/D.pickle.\n",
      "./notMNIST_large/D\n",
      "Could not read: ./notMNIST_large/D/VHJhbnNpdCBCb2xkLnR0Zg==.png : cannot identify image file './notMNIST_large/D/VHJhbnNpdCBCb2xkLnR0Zg==.png' - it's ok, skipping.\n",
      "Full dataset tensor: (52911, 28, 28)\n",
      "Mean: -0.0573678\n",
      "Standard deviation: 0.455648\n",
      "Pickling ./notMNIST_large/E.pickle.\n",
      "./notMNIST_large/E\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: -0.069899\n",
      "Standard deviation: 0.452942\n",
      "Pickling ./notMNIST_large/F.pickle.\n",
      "./notMNIST_large/F\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: -0.125583\n",
      "Standard deviation: 0.44709\n",
      "Pickling ./notMNIST_large/G.pickle.\n",
      "./notMNIST_large/G\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: -0.0945814\n",
      "Standard deviation: 0.44624\n",
      "Pickling ./notMNIST_large/H.pickle.\n",
      "./notMNIST_large/H\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: -0.0685221\n",
      "Standard deviation: 0.454232\n",
      "Pickling ./notMNIST_large/I.pickle.\n",
      "./notMNIST_large/I\n",
      "Full dataset tensor: (52912, 28, 28)\n",
      "Mean: 0.0307862\n",
      "Standard deviation: 0.468899\n",
      "Pickling ./notMNIST_large/J.pickle.\n",
      "./notMNIST_large/J\n",
      "Full dataset tensor: (52911, 28, 28)\n",
      "Mean: -0.153358\n",
      "Standard deviation: 0.443656\n",
      "Pickling ./notMNIST_small/A.pickle.\n",
      "./notMNIST_small/A\n",
      "Could not read: ./notMNIST_small/A/RGVtb2NyYXRpY2FCb2xkT2xkc3R5bGUgQm9sZC50dGY=.png : cannot identify image file './notMNIST_small/A/RGVtb2NyYXRpY2FCb2xkT2xkc3R5bGUgQm9sZC50dGY=.png' - it's ok, skipping.\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: -0.132626\n",
      "Standard deviation: 0.445128\n",
      "Pickling ./notMNIST_small/B.pickle.\n",
      "./notMNIST_small/B\n",
      "Full dataset tensor: (1873, 28, 28)\n",
      "Mean: 0.00535609\n",
      "Standard deviation: 0.457115\n",
      "Pickling ./notMNIST_small/C.pickle.\n",
      "./notMNIST_small/C\n",
      "Full dataset tensor: (1873, 28, 28)\n",
      "Mean: -0.141521\n",
      "Standard deviation: 0.44269\n",
      "Pickling ./notMNIST_small/D.pickle.\n",
      "./notMNIST_small/D\n",
      "Full dataset tensor: (1873, 28, 28)\n",
      "Mean: -0.0492167\n",
      "Standard deviation: 0.459759\n",
      "Pickling ./notMNIST_small/E.pickle.\n",
      "./notMNIST_small/E\n",
      "Full dataset tensor: (1873, 28, 28)\n",
      "Mean: -0.0599148\n",
      "Standard deviation: 0.45735\n",
      "Pickling ./notMNIST_small/F.pickle.\n",
      "./notMNIST_small/F\n",
      "Could not read: ./notMNIST_small/F/Q3Jvc3NvdmVyIEJvbGRPYmxpcXVlLnR0Zg==.png : cannot identify image file './notMNIST_small/F/Q3Jvc3NvdmVyIEJvbGRPYmxpcXVlLnR0Zg==.png' - it's ok, skipping.\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: -0.118185\n",
      "Standard deviation: 0.452279\n",
      "Pickling ./notMNIST_small/G.pickle.\n",
      "./notMNIST_small/G\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: -0.0925503\n",
      "Standard deviation: 0.449006\n",
      "Pickling ./notMNIST_small/H.pickle.\n",
      "./notMNIST_small/H\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: -0.0586893\n",
      "Standard deviation: 0.458759\n",
      "Pickling ./notMNIST_small/I.pickle.\n",
      "./notMNIST_small/I\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: 0.0526451\n",
      "Standard deviation: 0.471894\n",
      "Pickling ./notMNIST_small/J.pickle.\n",
      "./notMNIST_small/J\n",
      "Full dataset tensor: (1872, 28, 28)\n",
      "Mean: -0.151689\n",
      "Standard deviation: 0.448014\n"
     ]
    }
   ],
   "source": [
    "image_size = 28  # Pixel width and height.\n",
    "pixel_depth = 255.0  # Number of levels per pixel.\n",
    "\n",
    "def load_letter(folder, min_num_images):\n",
    "  \"\"\"Load the data for a single letter label.\"\"\"\n",
    "  image_files = os.listdir(folder)\n",
    "  dataset = np.ndarray(shape=(len(image_files), image_size, image_size),\n",
    "                         dtype=np.float32)\n",
    "  print(folder)\n",
    "  num_images = 0\n",
    "  for image in image_files:\n",
    "    image_file = os.path.join(folder, image)\n",
    "    try:\n",
    "      image_data = (ndimage.imread(image_file).astype(float) - \n",
    "                    pixel_depth / 2) / pixel_depth\n",
    "      if image_data.shape != (image_size, image_size):\n",
    "        raise Exception('Unexpected image shape: %s' % str(image_data.shape))\n",
    "      dataset[num_images, :, :] = image_data\n",
    "      num_images = num_images + 1\n",
    "    except IOError as e:\n",
    "      print('Could not read:', image_file, ':', e, '- it\\'s ok, skipping.')\n",
    "    \n",
    "  dataset = dataset[0:num_images, :, :]\n",
    "  if num_images < min_num_images:\n",
    "    raise Exception('Many fewer images than expected: %d < %d' %\n",
    "                    (num_images, min_num_images))\n",
    "    \n",
    "  print('Full dataset tensor:', dataset.shape)\n",
    "  print('Mean:', np.mean(dataset))\n",
    "  print('Standard deviation:', np.std(dataset))\n",
    "  return dataset\n",
    "        \n",
    "def maybe_pickle(data_folders, min_num_images_per_class, force=False):\n",
    "  dataset_names = []\n",
    "  for folder in data_folders:\n",
    "    set_filename = folder + '.pickle'\n",
    "    dataset_names.append(set_filename)\n",
    "    if os.path.exists(set_filename) and not force:\n",
    "      # You may override by setting force=True.\n",
    "      print('%s already present - Skipping pickling.' % set_filename)\n",
    "    else:\n",
    "      print('Pickling %s.' % set_filename)\n",
    "      dataset = load_letter(folder, min_num_images_per_class)\n",
    "      try:\n",
    "        with open(set_filename, 'wb') as f:\n",
    "          pickle.dump(dataset, f, pickle.HIGHEST_PROTOCOL)\n",
    "      except Exception as e:\n",
    "        print('Unable to save data to', set_filename, ':', e)\n",
    "  \n",
    "  return dataset_names\n",
    "\n",
    "train_datasets = maybe_pickle(train_folders, 45000)\n",
    "test_datasets = maybe_pickle(test_folders, 1800)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "vUdbskYE2d87"
   },
   "source": [
    "---\n",
    "Problem 2\n",
    "---------\n",
    "\n",
    "Let's verify that the data still looks good. Displaying a sample of the labels and images from the ndarray. Hint: you can use matplotlib.pyplot.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def disp_8_img(imgs, titles):\n",
    "  \"\"\"Display subplot with 8 images or less\"\"\"\n",
    "  for i, img in enumerate(imgs):\n",
    "    plt.subplot(2, 4, i+1)\n",
    "    plt.title(titles[i])\n",
    "    plt.axis('off')\n",
    "    plt.imshow(img)\n",
    "\n",
    "def disp_sample_pickles(data_folders):\n",
    "  folder = random.sample(data_folders, 1)\n",
    "  pickle_filename = ''.join(folder) + '.pickle'\n",
    "  try:\n",
    "    with open(pickle_filename, 'rb') as f:\n",
    "      dataset = pickle.load(f)\n",
    "  except Exception as e:\n",
    "    print('Unable to read data from', pickle_filename, ':', e)\n",
    "    return\n",
    "  # display\n",
    "  plt.suptitle(''.join(folder)[-1])\n",
    "  for i, img in enumerate(random.sample(list(dataset), 8)):\n",
    "    plt.subplot(2, 4, i+1)\n",
    "    plt.axis('off')\n",
    "    plt.imshow(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a06599b10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_sample_pickles(train_folders)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nBrv9uQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x102439650>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_sample_pickles(test_folders)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "cYznx5jUwzoO"
   },
   "source": [
    "---\n",
    "Problem 3\n",
    "---------\n",
    "Another check: we expect the data to be balanced across classes. Verify that.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Data is balanced across classes if the classes have about the same number of items. Let's check the number of images by class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of images in  ./notMNIST_large/A  :  52909\n",
      "Number of images in  ./notMNIST_large/B  :  52911\n",
      "Number of images in  ./notMNIST_large/C  :  52912\n",
      "Number of images in  ./notMNIST_large/D  :  52911\n",
      "Number of images in  ./notMNIST_large/E  :  52912\n",
      "Number of images in  ./notMNIST_large/F  :  52912\n",
      "Number of images in  ./notMNIST_large/G  :  52912\n",
      "Number of images in  ./notMNIST_large/H  :  52912\n",
      "Number of images in  ./notMNIST_large/I  :  52912\n",
      "Number of images in  ./notMNIST_large/J  :  52911\n",
      "Number of images in  ./notMNIST_small/A  :  1872\n",
      "Number of images in  ./notMNIST_small/B  :  1873\n",
      "Number of images in  ./notMNIST_small/C  :  1873\n",
      "Number of images in  ./notMNIST_small/D  :  1873\n",
      "Number of images in  ./notMNIST_small/E  :  1873\n",
      "Number of images in  ./notMNIST_small/F  :  1872\n",
      "Number of images in  ./notMNIST_small/G  :  1872\n",
      "Number of images in  ./notMNIST_small/H  :  1872\n",
      "Number of images in  ./notMNIST_small/I  :  1872\n",
      "Number of images in  ./notMNIST_small/J  :  1872\n"
     ]
    }
   ],
   "source": [
    "def disp_number_images(data_folders):\n",
    "  for folder in data_folders:\n",
    "    pickle_filename = ''.join(folder) + '.pickle'\n",
    "    try:\n",
    "      with open(pickle_filename, 'rb') as f:\n",
    "        dataset = pickle.load(f)\n",
    "    except Exception as e:\n",
    "      print('Unable to read data from', pickle_filename, ':', e)\n",
    "      return\n",
    "    print('Number of images in ', folder, ' : ', len(dataset))\n",
    "    \n",
    "disp_number_images(train_folders)\n",
    "disp_number_images(test_folders)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are only minor gaps, so the classes are well balanced."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "LA7M7K22ynCt"
   },
   "source": [
    "Merge and prune the training data as needed. Depending on your computer setup, you might not be able to fit it all in memory, and you can tune `train_size` as needed. The labels will be stored into a separate array of integers 0 through 9.\n",
    "\n",
    "Also create a validation dataset for hyperparameter tuning."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     },
     "output_extras": [
      {
       "item_id": 1
      }
     ]
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 411281,
     "status": "ok",
     "timestamp": 1444485897869,
     "user": {
      "color": "#1FA15D",
      "displayName": "Vincent Vanhoucke",
      "isAnonymous": false,
      "isMe": true,
      "permissionId": "05076109866853157986",
      "photoUrl": "//lh6.googleusercontent.com/-cCJa7dTDcgQ/AAAAAAAAAAI/AAAAAAAACgw/r2EZ_8oYer4/s50-c-k-no/photo.jpg",
      "sessionId": "2a0a5e044bb03b66",
      "userId": "102167687554210253930"
     },
     "user_tz": 420
    },
    "id": "s3mWgZLpyuzq",
    "outputId": "8af66da6-902d-4719-bedc-7c9fb7ae7948"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training: (200000, 28, 28) (200000,)\n",
      "Validation: (10000, 28, 28) (10000,)\n",
      "Testing: (10000, 28, 28) (10000,)\n"
     ]
    }
   ],
   "source": [
    "def make_arrays(nb_rows, img_size):\n",
    "  if nb_rows:\n",
    "    dataset = np.ndarray((nb_rows, img_size, img_size), dtype=np.float32)\n",
    "    labels = np.ndarray(nb_rows, dtype=np.int32)\n",
    "  else:\n",
    "    dataset, labels = None, None\n",
    "  return dataset, labels\n",
    "\n",
    "def merge_datasets(pickle_files, train_size, valid_size=0):\n",
    "  num_classes = len(pickle_files)\n",
    "  valid_dataset, valid_labels = make_arrays(valid_size, image_size)\n",
    "  train_dataset, train_labels = make_arrays(train_size, image_size)\n",
    "  vsize_per_class = valid_size // num_classes\n",
    "  tsize_per_class = train_size // num_classes\n",
    "    \n",
    "  start_v, start_t = 0, 0\n",
    "  end_v, end_t = vsize_per_class, tsize_per_class\n",
    "  end_l = vsize_per_class+tsize_per_class\n",
    "  for label, pickle_file in enumerate(pickle_files):       \n",
    "    try:\n",
    "      with open(pickle_file, 'rb') as f:\n",
    "        letter_set = pickle.load(f)\n",
    "        # let's shuffle the letters to have random validation and training set\n",
    "        np.random.shuffle(letter_set)\n",
    "        if valid_dataset is not None:\n",
    "          valid_letter = letter_set[:vsize_per_class, :, :]\n",
    "          valid_dataset[start_v:end_v, :, :] = valid_letter\n",
    "          valid_labels[start_v:end_v] = label\n",
    "          start_v += vsize_per_class\n",
    "          end_v += vsize_per_class\n",
    "                    \n",
    "        train_letter = letter_set[vsize_per_class:end_l, :, :]\n",
    "        train_dataset[start_t:end_t, :, :] = train_letter\n",
    "        train_labels[start_t:end_t] = label\n",
    "        start_t += tsize_per_class\n",
    "        end_t += tsize_per_class\n",
    "    except Exception as e:\n",
    "      print('Unable to process data from', pickle_file, ':', e)\n",
    "      raise\n",
    "    \n",
    "  return valid_dataset, valid_labels, train_dataset, train_labels\n",
    "            \n",
    "            \n",
    "train_size = 200000\n",
    "valid_size = 10000\n",
    "test_size = 10000\n",
    "\n",
    "valid_dataset, valid_labels, train_dataset, train_labels = merge_datasets(\n",
    "  train_datasets, train_size, valid_size)\n",
    "_, _, test_dataset, test_labels = merge_datasets(test_datasets, test_size)\n",
    "\n",
    "print('Training:', train_dataset.shape, train_labels.shape)\n",
    "print('Validation:', valid_dataset.shape, valid_labels.shape)\n",
    "print('Testing:', test_dataset.shape, test_labels.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "GPTCnjIcyuKN"
   },
   "source": [
    "Next, we'll randomize the data. It's important to have the labels well shuffled for the training and test distributions to match."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "collapsed": true,
    "id": "6WZ2l2tN2zOL"
   },
   "outputs": [],
   "source": [
    "def randomize(dataset, labels):\n",
    "  permutation = np.random.permutation(labels.shape[0])\n",
    "  shuffled_dataset = dataset[permutation,:,:]\n",
    "  shuffled_labels = labels[permutation]\n",
    "  return shuffled_dataset, shuffled_labels\n",
    "train_dataset, train_labels = randomize(train_dataset, train_labels)\n",
    "test_dataset, test_labels = randomize(test_dataset, test_labels)\n",
    "valid_dataset, valid_labels = randomize(valid_dataset, valid_labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "puDUTe6t6USl"
   },
   "source": [
    "---\n",
    "Problem 4\n",
    "---------\n",
    "Convince yourself that the data is still good after shuffling!\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To be sure that the data are still fine after the merger and the randomization, I will select one item and display the image alongside the label. Note: 0 = A, 1 = B, 2 = C, 3 = D, 4 = E, 5 = F, 6 = G, 7 = H, 8 = I, 9 = J."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "pretty_labels = {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J'}\n",
    "\n",
    "def disp_sample_dataset(dataset, labels):\n",
    "  items = random.sample(range(len(labels)), 8)\n",
    "  for i, item in enumerate(items):\n",
    "    plt.subplot(2, 4, i+1)\n",
    "    plt.axis('off')\n",
    "    plt.title(pretty_labels[labels[item]])\n",
    "    plt.imshow(dataset[item])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a073ae0d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_sample_dataset(train_dataset, train_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nrkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a14f5b550>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_sample_dataset(valid_dataset, valid_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\ngg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a14f0aa10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "disp_sample_dataset(test_dataset, test_labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "tIQJaJuwg5Hw"
   },
   "source": [
    "Finally, let's save the data for later reuse:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "collapsed": true,
    "id": "QiR_rETzem6C"
   },
   "outputs": [],
   "source": [
    "pickle_file = os.path.join(data_root, 'notMNIST.pickle')\n",
    "\n",
    "try:\n",
    "  f = open(pickle_file, 'wb')\n",
    "  save = {\n",
    "    'train_dataset': train_dataset,\n",
    "    'train_labels': train_labels,\n",
    "    'valid_dataset': valid_dataset,\n",
    "    'valid_labels': valid_labels,\n",
    "    'test_dataset': test_dataset,\n",
    "    'test_labels': test_labels,\n",
    "    }\n",
    "  pickle.dump(save, f, pickle.HIGHEST_PROTOCOL)\n",
    "  f.close()\n",
    "except Exception as e:\n",
    "  print('Unable to save data to', pickle_file, ':', e)\n",
    "  raise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     },
     "output_extras": [
      {
       "item_id": 1
      }
     ]
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 413065,
     "status": "ok",
     "timestamp": 1444485899688,
     "user": {
      "color": "#1FA15D",
      "displayName": "Vincent Vanhoucke",
      "isAnonymous": false,
      "isMe": true,
      "permissionId": "05076109866853157986",
      "photoUrl": "//lh6.googleusercontent.com/-cCJa7dTDcgQ/AAAAAAAAAAI/AAAAAAAACgw/r2EZ_8oYer4/s50-c-k-no/photo.jpg",
      "sessionId": "2a0a5e044bb03b66",
      "userId": "102167687554210253930"
     },
     "user_tz": 420
    },
    "id": "hQbLjrW_iT39",
    "outputId": "b440efc6-5ee1-4cbc-d02d-93db44ebd956"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Compressed pickle size: 690800441\n"
     ]
    }
   ],
   "source": [
    "statinfo = os.stat(pickle_file)\n",
    "print('Compressed pickle size:', statinfo.st_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "gE_cRAQB33lk"
   },
   "source": [
    "---\n",
    "Problem 5\n",
    "---------\n",
    "\n",
    "By construction, this dataset might contain a lot of overlapping samples, including training data that's also contained in the validation and test set! Overlap between training and test can skew the results if you expect to use your model in an environment where there is never an overlap, but are actually ok if you expect to see training samples recur when you use it.\n",
    "Measure how much overlap there is between training, validation and test samples.\n",
    "\n",
    "Optional questions:\n",
    "- What about near duplicates between datasets? (images that are almost identical)\n",
    "- Create a sanitized validation and test set, and compare your accuracy on those in subsequent assignments.\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this part, I will explore the datasets and understand better the overlap cases. There are overlaps, but there are also duplicates in the same dataset! Processing time is also critical. I will first use nested loops and matrix comparison, which is slow and then use hash function to accelerate and process the whole dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def display_overlap(overlap, source_dataset, target_dataset):\n",
    "  item = random.choice(overlap.keys())\n",
    "  imgs = np.concatenate(([source_dataset[item]], target_dataset[overlap[item][0:7]]))\n",
    "  plt.suptitle(item)\n",
    "  for i, img in enumerate(imgs):\n",
    "    plt.subplot(2, 4, i+1)\n",
    "    plt.axis('off')\n",
    "    plt.imshow(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def extract_overlap(dataset_1, dataset_2):\n",
    "  overlap = {}\n",
    "  for i, img_1 in enumerate(dataset_1):\n",
    "    for j, img_2 in enumerate(dataset_2):     \n",
    "      if np.array_equal(img_1, img_2):\n",
    "        if not i in overlap.keys():\n",
    "          overlap[i] = []\n",
    "        overlap[i].append(j)\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 5min 32s, sys: 7.94 s, total: 5min 40s\n",
      "Wall time: 6min 21s\n"
     ]
    }
   ],
   "source": [
    "%time overlap_test_train = extract_overlap(test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of overlaps: 24\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a07113190>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of overlaps:', len(overlap_test_train.keys()))\n",
    "display_overlap(overlap_test_train, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The display_overlap function above display one of the duplicate, the first element is from the first dataset, and the next ones are from the dataset used for the comparison.\n",
    "\n",
    "Now that exact duplicates have been found, let's look for near duplicates. How to define near identical images? That's a tricky question. My first thought has been to use the allclose numpy matrix comparison. This is too restrictive, since two images can vary by one pyxel, and still be very similar even if the variation on the pyxel is large. A better solution involves some kind of average.\n",
    "\n",
    "To keep is simple and still relevant, I will use a Manhattan norm (sum of absolute values) of the difference matrix. Since the images of the dataset have all the same size, I will not normalize the norm value. Note that it is pyxel by pyxel comparison, and therefore it will not scale to the whole dataset, but it will help to understand image similarities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "MAX_MANHATTAN_NORM = 10\n",
    "\n",
    "def extract_overlap_near(dataset_1, dataset_2):\n",
    "  overlap = {}\n",
    "  for i, img_1 in enumerate(dataset_1):\n",
    "    for j, img_2 in enumerate(dataset_2):\n",
    "      diff = img_1 - img_2\n",
    "      m_norm = np.sum(np.abs(diff))\n",
    "      if m_norm < MAX_MANHATTAN_NORM:\n",
    "        if not i in overlap.keys():\n",
    "          overlap[i] = []\n",
    "        overlap[i].append(j)\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 8min 52s, sys: 13.7 s, total: 9min 6s\n",
      "Wall time: 10min 13s\n"
     ]
    }
   ],
   "source": [
    "%time overlap_test_train_near = extract_overlap_near(test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of near overlaps: 53\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a074767d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of near overlaps:', len(overlap_test_train_near.keys()))\n",
    "display_overlap(overlap_test_train_near, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The techniques above work well, but the performance is very low and the methods are poorly scalable to the full dataset. Let's try to improve the performance. Let's take some reference times on a small dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here are some ideas:\n",
    "1 - stop a the first occurence\n",
    "2 - nympy function where in diff dataset\n",
    "3 - hash comparison"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def extract_overlap_stop(dataset_1, dataset_2):\n",
    "  overlap = {}\n",
    "  for i, img_1 in enumerate(dataset_1):\n",
    "    for j, img_2 in enumerate(dataset_2):     \n",
    "      if np.array_equal(img_1, img_2):\n",
    "        overlap[i] = [j]\n",
    "        break\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4min 44s, sys: 5.38 s, total: 4min 50s\n",
      "Wall time: 5min 8s\n"
     ]
    }
   ],
   "source": [
    "%time overlap_test_train = extract_overlap_stop(test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of overlaps: 24\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a073ae090>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of overlaps:', len(overlap_test_train.keys()))\n",
    "display_overlap(overlap_test_train, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is a faster, and only one duplicate from the second dataset is displayed. This is still not scalable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "MAX_MANHATTAN_NORM = 10\n",
    "\n",
    "def extract_overlap_where(dataset_1, dataset_2):\n",
    "  overlap = {}\n",
    "  for i, img_1 in enumerate(dataset_1):\n",
    "    diff = dataset_2 - img_1\n",
    "    norm = np.sum(np.abs(diff), axis=1)\n",
    "    duplicates = np.where(norm < MAX_MANHATTAN_NORM)\n",
    "    if len(duplicates[0]):\n",
    "      overlap[i] = duplicates[0]\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1min 22s, sys: 2min, total: 3min 23s\n",
      "Wall time: 3min 30s\n"
     ]
    }
   ],
   "source": [
    "test_flat = test_dataset.reshape(test_dataset.shape[0], 28 * 28)\n",
    "train_flat = train_dataset.reshape(train_dataset.shape[0], 28 * 28)\n",
    "%time overlap_test_train = extract_overlap_where(test_flat[:200], train_flat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of overlaps: 53\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a071261d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of overlaps:', len(overlap_test_train.keys()))\n",
    "display_overlap(overlap_test_train, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The built-in numpy function provides some improvement either, but this algorithm is still not scalable to the dataset to its full extend.\n",
    "\n",
    "To make it work at scale, the best option is to use a hash function. To find exact duplicates, the hash functions used for the cryptography will work just fine."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def extract_overlap_hash(dataset_1, dataset_2):\n",
    "  dataset_hash_1 = [hashlib.sha256(img).hexdigest() for img in dataset_1]\n",
    "  dataset_hash_2 = [hashlib.sha256(img).hexdigest() for img in dataset_2]\n",
    "  overlap = {}\n",
    "  for i, hash1 in enumerate(dataset_hash_1):\n",
    "    for j, hash2 in enumerate(dataset_hash_2):\n",
    "      if hash1 == hash2:\n",
    "        if not i in overlap.keys():\n",
    "          overlap[i] = []\n",
    "        overlap[i].append(j) ## use np.where\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 11 s, sys: 197 ms, total: 11.2 s\n",
      "Wall time: 11.9 s\n"
     ]
    }
   ],
   "source": [
    "%time overlap_test_train = extract_overlap_hash(test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of overlaps: 24\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nWACj/wNrQ7XC1dUJVQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a14d61ad0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of overlaps:', len(overlap_test_train.keys()))\n",
    "display_overlap(overlap_test_train, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More overlapping values could be found, this is due to the hash collisions. Several images can have the same hash but are actually different differents. This is not noticed here, and even if it happens, this is acceptable. All duplicates will be removed for sure.\n",
    "\n",
    "We can make the processing a but faster by using the built-in numpy wherefunction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def extract_overlap_hash_where(dataset_1, dataset_2):\n",
    "  dataset_hash_1 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_1])\n",
    "  dataset_hash_2 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_2])\n",
    "  overlap = {}\n",
    "  for i, hash1 in enumerate(dataset_hash_1):\n",
    "    duplicates = np.where(dataset_hash_2 == hash1)\n",
    "    if len(duplicates[0]):\n",
    "      overlap[i] = duplicates[0]\n",
    "  return overlap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2.9 s, sys: 71.1 ms, total: 2.97 s\n",
      "Wall time: 3.1 s\n"
     ]
    }
   ],
   "source": [
    "%time overlap_test_train = extract_overlap_hash_where(test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of overlaps: 24\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nP91i1GcP/g6DAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a066fefd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print('Number of overlaps:', len(overlap_test_train.keys()))\n",
    "display_overlap(overlap_test_train, test_dataset[:200], train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From my perspective near duplicates should also be removed in the sanitized datasets. My assumption is that \"near\" duplicates are very very close (sometimes just there is a one pyxel border of difference), and penalyze the training the same way the true duplicates do.\n",
    "\n",
    "That's being said, finding near duplicates with a hash function is not obvious. There are techniques for that, like \"locally sensitive hashing\", \"perceptual hashing\" or \"difference hashing\". There even are Python library available. Unfortunatly I did not have time to try them. The sanitized dataset generated below are based on true duplicates found with a cryptography hash function.\n",
    "\n",
    "For sanitizing the dataset, I change the function above by returning the clean dataset directly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def sanetize(dataset_1, dataset_2, labels_1):\n",
    "  dataset_hash_1 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_1])\n",
    "  dataset_hash_2 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_2])\n",
    "  overlap = [] # list of indexes\n",
    "  for i, hash1 in enumerate(dataset_hash_1):\n",
    "    duplicates = np.where(dataset_hash_2 == hash1)\n",
    "    if len(duplicates[0]):\n",
    "      overlap.append(i) \n",
    "  return np.delete(dataset_1, overlap, 0), np.delete(labels_1, overlap, None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2.98 s, sys: 57.2 ms, total: 3.04 s\n",
      "Wall time: 3.11 s\n",
      "Overlapping images removed:  24\n"
     ]
    }
   ],
   "source": [
    "%time test_dataset_sanit, test_labels_sanit = sanetize(test_dataset[:200], train_dataset, test_labels[:200])\n",
    "print('Overlapping images removed: ', len(test_dataset[:200]) - len(test_dataset_sanit))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The same value is found, so we can now sanetize the test and the train datasets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 24.6 s, sys: 414 ms, total: 25 s\n",
      "Wall time: 26 s\n",
      "Overlapping images removed:  1324\n"
     ]
    }
   ],
   "source": [
    "%time test_dataset_sanit, test_labels_sanit = sanetize(test_dataset, train_dataset, test_labels)\n",
    "print('Overlapping images removed: ', len(test_dataset) - len(test_dataset_sanit))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 27.2 s, sys: 877 ms, total: 28.1 s\n",
      "Wall time: 30.6 s\n",
      "Overlapping images removed:  1067\n"
     ]
    }
   ],
   "source": [
    "%time valid_dataset_sanit, valid_labels_sanit = sanetize(valid_dataset, train_dataset, valid_labels)\n",
    "print('Overlapping images removed: ', len(valid_dataset) - len(valid_dataset_sanit))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "pickle_file_sanit = 'notMNIST_sanit.pickle'\n",
    "\n",
    "try:\n",
    "  f = open(pickle_file_sanit, 'wb')\n",
    "  save = {\n",
    "    'train_dataset': train_dataset,\n",
    "    'train_labels': train_labels,\n",
    "    'valid_dataset': valid_dataset_sanit,\n",
    "    'valid_labels': valid_labels_sanit,\n",
    "    'test_dataset': test_dataset_sanit,\n",
    "    'test_labels': test_labels_sanit,\n",
    "    }\n",
    "  pickle.dump(save, f, pickle.HIGHEST_PROTOCOL)\n",
    "  f.close()\n",
    "except Exception as e:\n",
    "  print('Unable to save data to', pickle_file, ':', e)\n",
    "  raise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Compressed pickle size: 683292701\n"
     ]
    }
   ],
   "source": [
    "statinfo = os.stat(pickle_file_sanit)\n",
    "print('Compressed pickle size:', statinfo.st_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since I did not have time to generate clean sanitized datasets, I did not use the datasets generated above in the training of the my NN in the next assignments."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "L8oww1s4JMQx"
   },
   "source": [
    "---\n",
    "Problem 6\n",
    "---------\n",
    "\n",
    "Let's get an idea of what an off-the-shelf classifier can give you on this data. It's always good to check that there is something to learn, and that it's a problem that is not so trivial that a canned solution solves it.\n",
    "\n",
    "Train a simple model on this data using 50, 100, 1000 and 5000 training samples. Hint: you can use the LogisticRegression model from sklearn.linear_model.\n",
    "\n",
    "Optional question: train an off-the-shelf model on all the data!\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I have already used scikit-learn in a previous MOOC. It is a great tool, very easy to use!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "regr = LogisticRegression()\n",
    "X_test = test_dataset.reshape(test_dataset.shape[0], 28 * 28)\n",
    "y_test = test_labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 72.4 ms, sys: 15 ms, total: 87.3 ms\n",
      "Wall time: 120 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.50900000000000001"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sample_size = 50\n",
    "X_train = train_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_train = train_labels[:sample_size]\n",
    "%time regr.fit(X_train, y_train)\n",
    "regr.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nEjigE0JISPj/DlRdkjna6vwAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a14d61290>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pred_labels = regr.predict(X_test)\n",
    "disp_sample_dataset(test_dataset, pred_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 182 ms, sys: 3.98 ms, total: 186 ms\n",
      "Wall time: 198 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.6966"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sample_size = 100\n",
    "X_train = train_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_train = train_labels[:sample_size]\n",
    "%time regr.fit(X_train, y_train)\n",
    "regr.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 3.68 s, sys: 78.2 ms, total: 3.76 s\n",
      "Wall time: 4.89 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.83330000000000004"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sample_size = 1000\n",
    "X_train = train_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_train = train_labels[:sample_size]\n",
    "%time regr.fit(X_train, y_train)\n",
    "regr.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.73599999999999999"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_valid = valid_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_valid = valid_labels[:sample_size]\n",
    "regr.score(X_valid, y_valid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nY/6QUFUAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a075b7150>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pred_labels = regr.predict(X_valid)\n",
    "disp_sample_dataset(valid_dataset, pred_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 25.2 s, sys: 670 ms, total: 25.9 s\n",
      "Wall time: 27.4 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.85109999999999997"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sample_size = 5000\n",
    "X_train = train_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_train = train_labels[:sample_size]\n",
    "%time regr.fit(X_train, y_train)\n",
    "regr.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To train the model on all the data, we have to use another solver. SAG is the faster one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 16min 27s, sys: 21.4 s, total: 16min 48s\n",
      "Wall time: 17min 25s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.89319999999999999"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "regr2 = LogisticRegression(solver='sag')\n",
    "sample_size = len(train_dataset)\n",
    "X_train = train_dataset[:sample_size].reshape(sample_size, 784)\n",
    "y_train = train_labels[:sample_size]\n",
    "%time regr2.fit(X_train, y_train)\n",
    "regr2.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1009c5450>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pred_labels = regr.predict(X_test)\n",
    "disp_sample_dataset(test_dataset, pred_labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The accuracy may be weak compared to a deep neural net, but as my first character recognition technique, I find it already impressive!"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "default_view": {},
   "name": "1_notmnist.ipynb",
   "provenance": [],
   "version": "0.3.2",
   "views": {}
  },
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
